/*==============================================================================
 * AUTH: Matthew Baum, 9753095
 * 		Domenico Romano 5574331
 *     Samantha Graham 1120689
 * DATE: January-27-2012
 * EDIT: March-10-2012
 * DESC: Java class to hold Task data.
 *==============================================================================*/

package SOEN_Phase_2;

// W3C DOM Libraries
import org.w3c.dom.*;
import java.util.ArrayList;

public class Task {

    // Task data
    private int ID, duration, timeInvested, assigneeID;
    private String title, assignee;
    private boolean complete;

    // Subtasks
    private ArrayList<Task> subtasks;

    // Parent Task (null if top-level)
    private Task parent = null;


    /**
     * Constructor for a Task object
     *
     * @param  id A unique identifier
     * @param  dur Estimated time (in hours) to complete the task
     * @param  title A name for the Task
     * @param  assgn The name of the assignee this task is given to
     * @param  assgnID The unique identifier of the assignee this task is given to
     * @param  hours Number of hours worked on this task so far
     * @param  done Boolean flag indicating whether or not the task has been completed
     * @param  subs Array List of subtasks attached to the current task
     *
     * @return A newly constructed Task object
     *
     * @since January-27-2012
     */
    public Task(int id, int dur, String title, String assgn, int assgnID, int hours, boolean done, ArrayList<Task> subs)
    {
        ID = id;
        duration = dur;
        this.title = title;
        assignee = assgn;
        assigneeID = assgnID;
        timeInvested = hours;
        complete = done;
        subtasks = subs;

        // Set current Task as parent on all subtasks
        setParentOnSubtasks();
    }


    /**
     * Private helper to set "parent" attribute on all subtasks
     *
     * @return void
     */
    private void setParentOnSubtasks()
    {
        for(int i = 0; i != subtasks.size(); ++i)
        {
            subtasks.get(i).parent = this;
        }
    }


    /**
     * Static method to create a Task from an XML DOM node
     *
     * DESC: A Task is created for a top-level node, and then
     * a Task is recursively created for each Subtask
     *
     * @param task An XML DOM node of "task" type, parsed from an XML data file
     * @return The Task object constructed from the XML DOM node
     */
    public static Task getTaskFromXMLNode(Node task)
    {
        // Variables to init a task object:
        int ID = 0, duration = 0, timeInvested = 0, assigneeID = 0;
        String title = "", assignee = "";
        boolean done = false;
        ArrayList<Task> subtasks = new ArrayList<Task>();

        // Get the task attributes (ID AND duration)
        NamedNodeMap taskAttributes = task.getAttributes();

        // Get the child nodes (title AND assignee)
        NodeList taskContents = task.getChildNodes();
       
        // Get the task ID:
        ID = Integer.parseInt( taskAttributes.getNamedItem("ID").getNodeValue() );
        
        // Get the duration:
        duration = Integer.parseInt( taskAttributes.getNamedItem("duration").getNodeValue() );

        // Get the amount of time invested
        timeInvested = Integer.parseInt( taskAttributes.getNamedItem("worked").getNodeValue() );

        // Get the completion status of the Task
        done = Boolean.parseBoolean( taskAttributes.getNamedItem("complete").getNodeValue() );

        // Iterate over the child nodes
        for(int j = 0; j != taskContents.getLength(); ++j)
        {
            // Identify the node label
            String label = taskContents.item(j).getNodeName();
            
            // Set task title
            if( label.equals("title") )
            {
                title = taskContents.item(j).getTextContent();
            }
                    
            // Set task assignee
            else if( label.equals("assignee") )
            {
                assignee = taskContents.item(j).getTextContent();
                assigneeID = Integer.parseInt( taskContents.item(j).getAttributes().getNamedItem("ID").getNodeValue() );
            }
            
            // Subtasks
            else if( label.equals("subtasks") )
            {
            	NodeList subs = taskContents.item(j).getChildNodes();
            	for(int m = 0; m < subs.getLength(); m++)
            	{
            		// Recursively create Task objects and add them to the subtask vector
            		if(subs.item(m).getNodeName().equals("subtask"))
            		{
            			Node sss = subs.item(m);
            			Task subt = Task.getTaskFromXMLNode(sss);
                		subtasks.add(subt);
            		}
            		
            	}
            }
        }

        // Return Task object created from the values extracted from the XML DOM node
        return( new Task(ID, duration, title, assignee, assigneeID, timeInvested, done, subtasks) );
    }


    /**
     * Create XML data from a Task object, and append it to an XML document
     *
     * @param doc XML Document object to create a Task element from
     * @param isSub Boolean flag identifying the Task as a subtask
     * @return The Task object constructed from the XML DOM node
     */
    public Element toXML(Document doc, boolean isSub)
    {
        // Create the task/subtask element
        Element taskElement;
        
        if(isSub)
        {
            taskElement = doc.createElement("subtask");
        }
        else
        {
            taskElement = doc.createElement("task");
        }

        // Add the ID attribute
        String tempID = Integer.toString(getID());
        taskElement.setAttribute("ID", tempID);

        // Add the duration attribute
        String tempDuration = Integer.toString(getDuration());
        taskElement.setAttribute("duration", tempDuration);

        // Add the worked attribute
        String tempWorked = Integer.toString(getTimeInvested());
        taskElement.setAttribute("worked", tempWorked);

        // Add the complete attribute
        String tempComplete = Boolean.toString(getCompletion());
        taskElement.setAttribute("complete", tempComplete);

        // Create the title element
        Element titleElement = doc.createElement("title");
        titleElement.appendChild(doc.createTextNode(getTitle()));
        taskElement.appendChild(titleElement);

        // Create the assignee element
        Element assigneeElement = doc.createElement("assignee");
        assigneeElement.setAttribute("ID", Integer.toString( getAssigneeID() ) );
        assigneeElement.appendChild(doc.createTextNode(getAssignee()));
        taskElement.appendChild(assigneeElement);

        // Create subtasks element
        Element subtasksElement = doc.createElement("subtasks");

        // Recursively append a child element, for each subtask
        for(int i = 0; i != subtasks.size(); ++i)
        {
            subtasksElement.appendChild( subtasks.get(i).toXML(doc, true) );
        }

        // Append the subtasks element to the Task XML
        taskElement.appendChild(subtasksElement);

        return taskElement;
    }

    
    /**
     * Function used to remove a subtask from a task object's, subtask list
     *
     * @param ID The unique identifier of the Task to be removed
     * @return void
     */
    public void removeSubtask(int ID)
    {
        Task subtask;

        for(int i = 0; i != subtasks.size(); ++i)
        {
            subtask = subtasks.get(i);

            // If the correct task is found, remove and return
            if(subtask.ID == ID)
            {
                subtasks.remove(i);
                return;
            }
        }
    }


    /**
     * Remove the current Task object from its parent's list of subtasks
     *
     * This method delegates its behavior to "removeSubtask(int ID)"
     *
     * @return The Task object constructed from the XML DOM node
     */
    public void removeFromParent()
    {
        if(isSubtask())
        {
            parent.removeSubtask(ID);
        }
    }


    /**
     * Print a String representation of a Task
     *
     * @return A String representation of a Task
     */
    @Override
    public String toString()
    {
        return("TASK #" + ID + ": " + title + ".\tDuration: " + duration +
                ".\tAssigned to: " + assignee + ", " + assigneeID +
                "\nHOURS INVESTED: " + timeInvested + " COMPLETED: " + complete);
    }


    /**
     * Compute a hash code from a Task
     *
     * @return An integer hash code
     */
    @Override
    public int hashCode()
    {
        // Return the Task ID, which is assumed to be unique
        return ID;
    }


    /**
     * Compares two Tasks for equality, used in hash table
     *
     * @param other Object representing another item to compare the task to
     * @return Boolean equality result
     */
    @Override
    public boolean equals(Object other)
    {
        // Tasks are considered equal if they have the same ID
        if(this != other && other instanceof Task)
        {
            Task otherTask = (Task)other;

            if(this.ID == otherTask.ID)
            {
                return true;
            }
        }
        
        // They are not considered equal!
        return false;
    }

    // GETTERS AND SETTERS
    public int getID() {
		return ID;
	}

	public int getDuration() {
		return duration;
	}

	public String getTitle() {
		return title;
	}

	public String getAssignee() {
		return assignee;
	}

    public int getAssigneeID()
    {
        return assigneeID;
    }

    public int getTimeInvested()
    {
        return timeInvested;
    }

    public boolean getCompletion()
    {
        return complete;
    }

    public ArrayList<Task> getSubtasks()
    {
        return subtasks;
    }

    public void setID(int id) {
		ID = id;
	}

	public void setDuration(int dur) {
		duration = dur;
	}

	public void setTitle(String ttl) {
		title = ttl;
	}

	public void setAssignee(String assgn) {
		assignee = assgn;
	}

    public void setAssigneeID(int id)
    {
        assigneeID = id;
    }

    public void setTimeInvested(int time)
    {
        timeInvested = time;
    }
    
    public Task getParent()
    {
    	return parent;
    }
    
    public void addSubtask(Task st)
    {
    	subtasks.add(st);
    	setParentOnSubtasks();
    }

    public void addTimeInvested(int time)
    {
        timeInvested += time;
    }

    public void setCompletion(boolean done)
    {
        complete = done;
    }

    // Return subtask status flag
    public boolean isSubtask()
    {
        return (parent != null);
    }
}
